package com.firewolf.rbac.config;

import com.firewolf.rbac.security.CustomUserDetailService;
import com.firewolf.rbac.security.FirewolfAccessDeniedHandler;
import com.firewolf.rbac.verifycode.ImageCodeVerifyFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import java.util.List;

/**
 * 作者：刘兴
 * 时间:19/3/5
 **/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    @Qualifier("customUserDetailService")
    private UserDetailsService userDetailsService;

    @Autowired
    private PersistentTokenRepository rersistentTokenRepository;


    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;


    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;


    @Autowired
    private ImageCodeVerifyFilter imageCodeVerifyFilter;
//
//    @Autowired
//    private AuthenticationDetailsSource authenticationDetailsSource;

    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(imageCodeVerifyFilter, UsernamePasswordAuthenticationFilter.class)
                .formLogin().loginPage("/login") //设置登录页，在这个请求里面返回页面路径
                .successHandler(authenticationSuccessHandler) //成功处理器
                .failureHandler(authenticationFailureHandler) //失败处理器
                .usernameParameter("username")
                .passwordParameter("password")
                .and()
                .rememberMe() //记住我
                .tokenRepository(rersistentTokenRepository)//设置token repository
                .tokenValiditySeconds(60)//token有效时间
                .and()
                .authorizeRequests() //对请求的路径进行认证
                .antMatchers("/login.html", "/login", "/verifycode/image","/403.html").permitAll() //需要放过的页面
                .anyRequest().authenticated() //其他的全部都需要认证
                .and()
                .logout().permitAll(); //放过退出请求
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
        http.csrf().disable(); // 关闭CSRF跨域
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
//        auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
//            @Override
//            public String encode(CharSequence charSequence) {
//                return charSequence.toString();
//            }
//
//            @Override
//            public boolean matches(CharSequence charSequence, String s) {
//                return s.equals(charSequence.toString());
//            }
//        });
    }



    @Bean("inMemoryUserDetailsService")
    public UserDetailsService inMemoryUserDetailsService() {
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,develop");
        String password = new BCryptPasswordEncoder().encode("123456");
        userDetailsManager.createUser(new User("zhangsan", password, authorities));
        userDetailsManager.createUser(new User("lisi", password, authorities));
        userDetailsManager.createUser(new User("wangwu", password, authorities));
        return userDetailsManager;
    }

    @Bean("jdbcUserDetailsService")
    public UserDetailsService jdbcUserDetailsService() {
        JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager();
        jdbcUserDetailsManager.setJdbcTemplate(jdbcTemplate);
        jdbcUserDetailsManager.setUsersByUsernameQuery("select name,password,enabled from sys_user where name = ?");
        jdbcUserDetailsManager.setAuthoritiesByUsernameQuery("xxxx"); //设置权限语句
        return jdbcUserDetailsManager;
    }

    @Bean("customUserDetailService")
    public UserDetailsService customUserDetailService() {
        return new CustomUserDetailService();
    }

    /**
     * Token持久化
     *
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setJdbcTemplate(jdbcTemplate);
        return jdbcTokenRepository;
    }
}
